===============================================================================
Universal Doom Map Format Specification v1.1 - 03/29/09

Written by James "Quasar" Haley - haleyjd@hotmail.com

Defined with input from:

CodeImp
esselfortium
Graf Zahl
Kaiser
SlayeR
SoM
et al.

    Copyright (c) 2009 James Haley.
    Permission is granted to copy, distribute and/or modify this document
    under the terms of the GNU Free Documentation License, Version 1.2
    or any later version published by the Free Software Foundation;
    with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
    
===============================================================================


=======================================
Preface
=======================================

The Universal Doom Map Format specification is a collaborative effort to 
create and maintain a cross-port standardized textual representation for Doom
engine maps. 

The basic UDMF standard contains a superset of the features of all commercial 
Doom engine games, and provides facilities for seamless extension in source 
ports, allowing in-editor access to custom map data which would otherwise be 
squirreled away in external lumps.


=======================================
Changes in v1.1
=======================================

This is version 1.1 of the UDMF specification, superceding the previous version
1.0 with the following adjustments:

* Added Preface.
* Grammar for identifiers altered to forbid initial numerals.
* Made use of true/false keywords for boolean-type fields more explicit.
* Rule added for user-defined fields.


=======================================
I. Grammar / Syntax
=======================================

    translation_unit := global_expr_list
    global_expr_list := global_expr global_expr_list
    global_expr := block | assignment_expr
    block := identifier '{' expr_list '}'
    expr_list := assignment_expr expr_list
    assignment_expr := identifier '=' value ';' | nil
    identifier := [A-Za-z_]+[A-Za-z0-9_]*
    value := integer | float | quoted_string | keyword
    integer := [+-]?[1-9]+[0-9]* | 0[0-9]+ | 0x[0-9A-Fa-f]+
    float := [+-]?[0-9]+'.'[0-9]*([eE][+-]?[0-9]+)?
    quoted_string := "([^"\\]*(\\.[^"\\]*)*)"
    keyword := [^{}();"'\n\t ]+


Global assignments and named/indexed global blocks are the only top-level
entities supported. Whitespace is strictly ignored.

Keywords are currently restricted to the values true and false, which are
used as the values of all boolean fields.

Comments are supported as C-style single and multi-line comments:

    // single line comment
    
    /*
       multi
       line
       comment
    */
    
Multi-line comments may not be nested.

Implementing editors are not required (but are allowed) to maintain syntactic
comments when rewriting UDMF map lumps. These comments are provided chiefly for
hand-writing and debugging purposes.

Blocks begin with a keyword identifier. An example of a minimally-defined
entity follows:

    linedef { id = 1; }

Compliant parsers will ignore all unknown keywords in global assignments, 
block-level assignments, and block headers. Compliant parsers should attempt
to preserve as much of such information as is possible by using a flexible
mapping such as hashing.

For purposes of forward compatibility, user-defined fields are restricted to
beginning with the string "user_", but are otherwise normal identifiers.
Implementing editors should not restrict the entry of custom field names to 
those beginning with "user_", however, in order to avoid problems with 
out-of-date configurations.

Identifiers and keywords are to be treated as case-insensitive.

A field which specifies "boolean" semantics shall accept keyword value 
true to mean that the field is asserted, and keyword value false to 
mean that the field is unasserted. Keyword values can only be defined in
this specification, and not by implementing ports. Use quoted strings
instead.

Fields which do not appear in a block take on their default value. This
allows minimal specification. Note that the default values specified by
UDMF are not necessarily the default values which editors may wish to
apply to those fields during the creation of new entities during editing.
Such editing defaults are not part of this specification.


=======================================
II. Implementation Semantics
=======================================

------------------------------------
II.A : Storage and Retrieval of Data
------------------------------------

Block-defined entities are written and read in top-to-bottom order. For
example, the following linedefs can be assigned in order to a contiguous
block of memory serving as the implementing port's lines array:

    linedef { id = 1; }
    linedef { id = 2; }
    linedef { id = 3; }
    linedef { id = 4; }
    
Data types:

For purposes of internal storage:
---------------------------------
Integers should be considered signed with a range of at least 32 bits.
Floating-point numbers should be considered double precision.
Strings have no reasonable length limitations.

Hard Data Type Limits
---------------------
No limits on number of definitions are defined as part of this specification,
but implementors may face the need to impose such limitations due to 
restrictions on the amount of memory available, or the amount that can be
allocated through a single pointer on the host machine or in a private heap
implementation.

In the event that a map exceeds such an internal engine limitation, an 
implementing port or editor should not continue to attempt loading the map, as
doing so could destabilize the program.

-----------------------------------
II.B : Storage Within Archive Files
-----------------------------------

UDMF maps shall be layed out within the archive directory as follows:

    (HEADER)
    TEXTMAP
    ... 
    ENDMAP

(HEADER) = Any lump name from 1 to 8 characters. Serves as the name of the map.
TEXTMAP  = Single UDMF lump containing all data for the map.
...      = Blockmap, reject, BSP tree, and port-specific lumps, if any. The
           format and presence of these resources are not defined by UDMF.
ENDMAP   = Required closing lump.

Implementing editors and source ports may distinguish a UDMF map from a
traditional binary map by testing the name of the first directory entry
following the map header. Implementing resource editors will be capable of
keeping all lumps for the map, even non-standard ones, together by properly
scanning for the ENDMAP entry. Non-implementing resource editors will not
recognize the sequence of lumps as a map, and may thus be less likely to
interfere with the order or presence of the lumps.

Use of non-implementing resource editors to manipulate UDMF-map-containing WAD
files is not recommended, however.
    
    
--------------------------------
II.C : Implementation Dependence
--------------------------------

A port's list of supported non-standard fields must be provided to implementing
editors, where they can be provided to the end user as controls, as options
in a dropbox, or through the ability to input any arbitrary 
"identifier = value;" pair in a text box.

Every UDMF map should contain as the first statement in the file the "namespace"
identifier statement, which declares the source port implementation relative to 
which this map is to be interpreted.

Example:

    namespace = "ZDoom";
    
Implementing source ports may ignore this information, or they may use it to 
perform automatic runtime translation of maps they would otherwise be unable to 
support.

Implementing source ports should publicly document the value of the "namespace"
variable they intend to identify with when establishing support for UDMF, and
avoid conflicts with existing implementations at all costs.

The following namespaces are considered reserved for compatibility purposes:

Doom
Heretic
Hexen
Strife

The use of one of these namespaces indicates that all line specials, sector 
specials, thing types, and if applicable, thing specials contained in the UDMF 
map conform to the "vanilla" types for the respective gamemode (with an 
exception for Doom) and are therefore 100% compatible with all UDMF 
implementors which support the specified gamemode.

An exception is made for the "Doom" translation type. It is considered to
represent the final fork of the v1.9 Doom engine, and therefore it includes
all line types added in DOOM II. It is also additionally considered to 
include all specials defined in the BOOM and MBF source ports. Implementors
who support BOOM linedef types can handle these in the normal manner; ports
which do not support them should zero or otherwise ignore the offending
specials.

Documentation of the precise meanings of these standardized namespaces will
be provided in separate documents.

This feature is provided in order to facilitate a universal and lossless
conversion of all existing Doom-engine-game maps to and from UDMF format,
independent of any implementing ports' specific namespaces.


=======================================
III. Standardized Fields
=======================================

The UDMF v1.0 specification considers the following fields standard. They must
be recognized by all implementing ports and editors (support for the features
they signify is not necessarily required, such as for ports which do not
implement Hexen support - all fields unknown to a given port should be 
ignored and not treated as an error).

All boolean fields take the keyword values true and false.

   linedef
   {
      id = <integer>; // ID of line. Interpreted as tag or scripting id.
                      // Default = -1. *** see below.
      
      v1 = <integer>; // Index of first vertex. No valid default.
      v2 = <integer>; // Index of second vertex. No valid default.
      
      // All flags default to false.
      
      blocking      = <bool>; // true = line blocks things.
      blockmonsters = <bool>; // true = line blocks monsters.
      twosided      = <bool>; // true = line is 2S.
      dontpegtop    = <bool>; // true = upper texture unpegged.
      dontpegbottom = <bool>; // true = lower texture unpegged.
      secret        = <bool>; // true = drawn as 1S on map.
      blocksound    = <bool>; // true = blocks sound.
      dontdraw      = <bool>; // true = line never drawn on map.
      mapped        = <bool>; // true = always appears on map.
      
      // BOOM passuse flag not supported in Strife/Heretic/Hexen namespaces.
      
      passuse       = <bool>; // true = passes use action.

      // Strife specific flags. Support for other games is not defined by
      // default and these flags should be ignored when reading maps not for
      // the Strife namespace or maps for a port which supports these flags.

      translucent   = <bool>; // true = line is a Strife translucent line.
      jumpover      = <bool>; // true = line is a Strife railing.
      blockfloaters = <bool>; // true = line is a Strife float-blocker.
      
      // Note: SPAC flags should be set false in Doom/Heretic/Strife
      // namespace maps. Specials in those games do not support this
      // mechanism and instead imply activation parameters through the
      // special number. All flags default to false.
      
      playercross   = <bool>; // true = player can cross.
      playeruse     = <bool>; // true = player can use.
      monstercross  = <bool>; // true = monster can cross.
      monsteruse    = <bool>; // true = monster can use.
      impact        = <bool>; // true = projectile can activate.
      playerpush    = <bool>; // true = player can push.
      monsterpush   = <bool>; // true = monster can push.
      missilecross  = <bool>; // true = projectile can cross.
      repeatspecial = <bool>; // true = repeatable special.
      
      special = <integer>; // Special. Default = 0.
      arg0    = <integer>; // Argument 0. Default = 0.
      arg1    = <integer>; // Argument 1. Default = 0.
      arg2    = <integer>; // Argument 2. Default = 0.
      arg3    = <integer>; // Argument 3. Default = 0.
      arg4    = <integer>; // Argument 4. Default = 0.
      
      sidefront = <integer>; // Sidedef 1 index. No valid default.
      sideback  = <integer>; // Sidedef 2 index. Default = -1.
      
      comment = <string>; // A comment. Implementors should attach no special
                          // semantic meaning to this field.
   }
   
   sidedef
   {
      offsetx = <integer>; // X Offset. Default = 0.
      offsety = <integer>; // Y Offset. Default = 0.
      
      texturetop    = <string>; // Upper texture. Default = "-".
      texturebottom = <string>; // Lower texture. Default = "-".
      texturemiddle = <string>; // Middle texture. Default = "-".
      
      sector = <integer>; // Sector index. No valid default.

      comment = <string>; // A comment. Implementors should attach no special
                          // semantic meaning to this field.
   }
   
   vertex
   {
      x = <float>; // X coordinate. No valid default.
      y = <float>; // Y coordinate. No valid default.
   }
   
   sector
   {
      heightfloor   = <integer>; // Floor height. Default = 0.
      heightceiling = <integer>; // Ceiling height. Default = 0.
      
      texturefloor   = <string>; // Floor flat. No valid default.
      textureceiling = <string>; // Ceiling flat. No valid default.
      
      lightlevel = <integer>; // Light level. Default = 160.
      
      special = <integer>; // Sector special. Default = 0.
      id      = <integer>; // Sector tag/id. Default = 0.

      comment = <string>; // A comment. Implementors should attach no special
                          // semantic meaning to this field.
   }
   
   thing
   {
      id = <integer>; // Thing ID. Default = 0.
      
      x = <float>; // X coordinate. No valid default.
      y = <float>; // Y coordinate. No valid default.
      
      height = <float>; // Z height relative to floor. Default = 0.
                        // (Relative to ceiling for SPAWNCEILING items).
                          
      angle = <integer>; // Map angle of thing in degrees. Default = 0 (East).
      
      type = <integer>; // DoomedNum. No valid default.
      
      // All flags default to false.
      
      skill1      = <bool>; // true = in skill 1.
      skill2      = <bool>; // true = in skill 2.
      skill3      = <bool>; // true = in skill 3.
      skill4      = <bool>; // true = in skill 4.
      skill5      = <bool>; // true = in skill 5.
      ambush      = <bool>; // true = thing is deaf.
      single      = <bool>; // true = in SP mode.
      dm          = <bool>; // true = in DM mode.
      coop        = <bool>; // true = in Coop.

      // MBF friend flag not supported in Strife/Heretic/Hexen namespaces.
      
      friend      = <bool>; // true = MBF friend.
      
      // Hexen flags; not supported in Doom/Strife/Heretic namespaces.
      
      dormant     = <bool>; // true = dormant thing.
      class1      = <bool>; // true = Present for pclass 1.
      class2      = <bool>; // true = Present for pclass 2.
      class3      = <bool>; // true = Present for pclass 3.
      

      // Strife specific flags. Support for other games is not defined by
      // default and these flags should be ignored when reading maps not for
      // the Strife namespace or maps for a port which supports these flags.
      standing    = <bool>; // true = Strife NPC flag.
      strifeally  = <bool>; // true = Strife ally flag.
      translucent = <bool>; // true = Strife translucency flag.
      invisible   = <bool>; // true = Strife invisibility flag.
            
      // Note: suggested editor defaults for all skill, gamemode, and player
      // class flags is true rather than the UDMF default of false.

      // Thing special semantics are only defined for the Hexen namespace or
      // ports which implement this feature in their own namespace.
      
      special = <integer>; // Scripting special. Default = 0;
      arg0    = <integer>; // Argument 0. Default = 0.
      arg1    = <integer>; // Argument 1. Default = 0.
      arg2    = <integer>; // Argument 2. Default = 0.
      arg3    = <integer>; // Argument 3. Default = 0.
      arg4    = <integer>; // Argument 4. Default = 0.

      comment = <string>; // A comment. Implementors should attach no special
                          // semantic meaning to this field.
   }
   

*** Tag / ID Behavior for Map Conversion:
   
   Unlike traditional Doom maps UDMF makes a clear distinction between a line's
   ID and the parameter which identifies the object the line's special is 
   supposed to affect.

   The id will be used to identify this line, and arg0 will be used to identify
   the line or sector that this line is to affect or otherwise reference, i.e.
   it is effectively a parameter to the line's special.

   Boom used the linedef's tag for both due to lack of other options so in 
   order to ensure compatibility any map converter converting maps for the 
   Doom/Heretic/Strife namespaces must store the linedef's tag field as both
   the id and as arg0 in each line. The default value of the id field under 
   these namespaces is defined as 0 rather than -1.
   
   Since UDMF provides a line id field, the Hexen line special #121
   (Line_SetIdentification) is obsolete. When converting maps to UDMF under
   Hexen namespace, special 121 should be written as zero, and the arg0 of
   the binary linedef should be written as the id field of the UDMF line.
   The arg0 value of the UDMF line should also then be set to zero.
   
===============================================================================
EOF
===============================================================================
